package tpcompiladores;

import AccionesSemanticas.*;
import java.io.FileInputStream;
import java.util.Vector;

public class Lexico {

    //Final State
    private final int F = 99;
    //Error State
    private final int E = -1; 
    //Token Constant Declaration
    private final static short IF=257;
    private final static short THEN=258;
    private final static short ELSE=259;
    private final static short PRINT=260;
    private final static short VAR=261;
    private final static short ARRAY=262;
    private final static short DOUBLE=263;
    private final static short DO=264;
    private final static short UNTIL=265;
    private final static short ASIG=266;
    private final static short MAYI=267;
    private final static short MAY=268;
    private final static short DIST=269;
    private final static short MENI=270;
    private final static short MEN=271;
    private final static short IDENTIFICADOR=272;
    private final static short DOUB=273;
    private final static short CADENA=274;
    private final static char EOF= 0;
    //Buffer of the code to compile
    private char[] buffer;
    //Characters that belong to the current token
    private StringBuilder tokenChars;
    //Transition Matrix
    private int[][] transitions;
    //Actions Matrix
    private int[][] actions;
    //Actions Vector
    private Vector<AccSemantica> acciones;
    //Table of Symbols
    private TablaSimb table;
    //Last position read
    private int[] lastRead;
    //Current State
    private int currentState;
    //Last State
    private int[] lastState;
    //Line number
    private int[] lineNumber;
    //
    private boolean truncado = false;
    //Log de errores
    private Vector<String> errors;
   
    public Lexico(FileInputStream file, TablaSimb table){
        //Indicates the last read position of the char[]
        errors = new Vector<String>();
        lastRead = new int[1];
        lastRead[0] = 0;System.out.println(EOF);
        lineNumber = new int[1];
        lineNumber[0] = 1;
        
        tokenChars = new StringBuilder();
        
        //Symbol Table
        this.table = table;
        
        //Current and Last state initialized to 0 (Initial State)
        lastState = new int[1];
        lastState[0] = 0;
        this.currentState = 0;
        
        //Copy all the file contents into a char[] called buffer
        try{
            this.buffer = new char[file.available()+1];
            int pos = 0;
            while(file.available() > 0){
                buffer[pos] = (char) file.read();
                pos++;
            }
            buffer[pos] = (char) EOF;
        }
        catch(Exception e){
            e.printStackTrace();
        }

        acciones = new Vector<AccSemantica>();
        AccTruncar atrunc = new AccTruncar(tokenChars,truncado);
        AccLReadMinus1 aLRMOne = new AccLReadMinus1(lastRead);
        AccDelLastTokenChar aDLTChar = new AccDelLastTokenChar(tokenChars);
        AccDelTokenChars aDTChars = new AccDelTokenChars(tokenChars);
        AccLastToCurrentState aLTCState = new AccLastToCurrentState(lastState, currentState);
        AccLinePlusOne aLPOne = new AccLinePlusOne(lineNumber);
        AccErrors aErr = new AccErrors(lineNumber,tokenChars,lastState);
        AccSimbolTable aSTableV = new AccSimbolTable(tokenChars, "VARIABLE", table);
        AccSimbolTableC aSTableC = new AccSimbolTableC(tokenChars, "CTE DOUBLE", table);        
        AccSimbolTable aSTableS = new AccSimbolTable(tokenChars, "CADENA", table);        
        AccDoubleRange aDRange = new AccDoubleRange(tokenChars,lineNumber);
        //0
        acciones.add(atrunc);
        //1
        acciones.add(aLRMOne);
        //2
        acciones.add(aDLTChar);
        Vector<AccSemantica> comp = new Vector<>();
        comp.add(aLRMOne);
        comp.add(aDLTChar);
        //3 = 1 + 2
        acciones.add(new AccComp(comp));
        //4
        acciones.add(aDTChars);
        //5
        acciones.add(aLTCState);
        Vector<AccSemantica> comp1 = new Vector<>();
        comp1.add(aLRMOne);
        comp1.add(aDLTChar);
        comp1.add(aLPOne);
        //6 = 1 + 2 + aLPOne
        acciones.add(new AccComp(comp1));
        Vector<AccSemantica> comp2 = new Vector<>();
        comp2.add(aLRMOne);
        comp2.add(aErr);
       // comp2.add(aLPOne);
        //7 = 1 + aErr
        acciones.add(new AccComp(comp2));
        //8 aErr
        acciones.add(aErr);        
        Vector<AccSemantica> comp3 = new Vector<>();
        comp3.add(aLRMOne);
        comp3.add(aDLTChar);
        //comp3.add(aSTableV);
        //9 = 1 + 2 + aSTable
        acciones.add(new AccComp(comp3));
        Vector<AccSemantica> comp4 = new Vector<>();
        comp4.add(aLRMOne);
        comp4.add(aDLTChar);
        comp4.add(aDRange);
        comp4.add(aSTableC);
        //10 = 1 + 2 + aDRange
        acciones.add(new AccComp(comp4));
        Vector<AccSemantica> comp5 = new Vector<>();
        comp5.add(aLPOne);
        comp5.add(aDLTChar);
        acciones.add(new AccComp(comp5));
        Vector<AccSemantica> comp6 = new Vector<>();
        comp6.add(aErr);
        comp6.add(aLRMOne);
        acciones.add(new AccComp(comp6));
        acciones.add(aSTableS);
        /*
         * SEMANTIC ACTIONS in acciones vector by positions
         * 0  - Checks length < 12 (atrunc)
         * 1  - LastRead -1 (aLRMOne)
         * 2  - Removes last whitespace (aDLTChar)
         * 3  - 1 & 2 (aLRMOne & aDLTChar)
         * 4  - Resets tokenChars to "" (aDTChars)
         * 5  - Switches currentState with lastState (aLTCState)
         * 6  - aLRMOne & aDLTChar & aLPOne
         * 7  - aLRMOne & aErr
         * 8  - Prints error and deletes tokenChars buffer (aErr)
         * 9  - aLRMOne & aDLTChar & aSTableV
         * 10 - aLRMOne & aDLTChar & aDRange & aSTableC
         * 11 - aLPOne & aDLTChars
         * 12 - aLPOne & aDLTChars & aLRMOne
         * 13 - aSTableS
         */
        
        //                         L  D  +  -  *  /  <  >  =  [  ]  (  )  {  }  ;  ,  .  :     1  2  "  d EoF \t
        transitions = new int[][]{{1 ,9 ,F ,F,5 ,F ,4 ,3 ,F ,F ,F ,F ,F ,F ,F ,F ,F ,10,2 ,0 ,8 ,0 ,15,1 ,F ,0 }, //E0
                                  {1 ,1 ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,1 ,F ,F }, //E1
                                  {0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,F ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,F ,0 }, //E2
                                  {F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F }, //E3
                                  {F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F }, //E4
                                  {F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,6 ,F ,F ,F ,F ,F ,F ,E ,F ,F ,F ,F ,5 }, //E5
                                  {6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,7 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,0 ,6 }, //E6
                                  {6 ,6 ,6 ,6 ,0 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,7 ,6 ,6 ,6 ,6 ,6 ,7 ,7 ,6 ,6 ,0 ,7 }, //E7
                                  {E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,0 ,E ,E ,F ,0 }, //E8
                                  {0 ,9 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,11,0 ,0 ,0 ,0 ,0 ,13,F ,0 }, //E9
                                  {0 ,12,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,F ,0 }, //E10
                                  {F ,12,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,13,F ,F }, //E11
                                  {F ,12,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,13,F ,F }, //E12
                                  {0 ,14,14,14,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,F ,0 }, //E13
                                  {F ,14,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F ,F }, //E14
                                  {15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,0 ,0 ,F ,15,0 ,15}, //E15
                                };
        
        //                     L  D  +  -  *  /  <  >  =  [  ]  (  )  {  }  ;  ,  .  :     1  2  "  d EoF \t
        actions = new int[][]{{E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,4 ,4 ,11,E ,E ,E ,4 }, //E0
                              {0 ,0 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,11,9 ,0 ,5 ,2 }, //E1
                              {12,12,12,12,12,12,12,12,E ,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,E ,12}, //E2
                              {3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,E ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,6 ,3 ,3 ,E ,2 }, //E3
                              {3 ,3 ,3 ,3 ,3 ,3 ,3 ,E ,E ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,6 ,3 ,3 ,E ,2 }, //E4
                              {E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,7 ,E ,E ,E ,E ,E }, //E5
                              {E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,7 ,E }, //E6
                              {E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,7 ,E }, //E7
                              {E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,7 ,6 ,E ,E ,E ,2 }, //E8                
                              {7 ,E ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,E ,7 ,7 ,7 ,7 ,7 ,E ,7 ,7 }, //E9                              
                              {7 ,E ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 }, //E10                              
                              {10,E ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,6 ,10,E ,E ,2 }, //E11
                              {10,E ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,6 ,10,E ,E ,2 }, //E12
                              {7 ,E ,E ,E ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,3 ,6 ,7 ,7 ,7 ,7 }, //E13
                              {10,E ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,6 ,10,10,E ,2 }, //E14
                              {E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,E ,7 ,7 ,13,E ,7 ,E },//E15
                            };    
    }   
    
    public int mapChar(char c){
        String s = c + "";
        c = s.toLowerCase().charAt(0);
        switch(c){
            case 'a': case 'b':case 'c': case 'e': case 'f':case 'g': case 'h':
            case 'i': case 'j':case 'k': case 'l':case 'm': case 'n':case 'o': case 'p':
            case 'q': case 'r':case 's': case 't':case 'u': case 'v':case 'w': case 'x':
            case 'y': case 'z':case '!':
                return 0;
            case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
                return 1;
            case '+':
                return 2;
            case '-':
                return 3;
            case '*':
                return 4;
            case '/':
                return 5;
            case '<':
                return 6;
            case '>':
                return 7;
            case '=':
                return 8;
            case '[':
                return 9;
            case ']':
                return 10;
            case '(':
                return 11;
            case ')':
                return 12;
            case '{':
                return 13;
            case '}':
                return 14;
            case ';':
                return 15;
            case ',':
                return 16;
            case '.':
                return 17;
            case ':':
                return 18;
            case ' ':
                return 19;
            case 13:
                return 20;
            case 10:
                return 21;
            case '"': 
                return 22;
            case 'd':
                return 23;
            case EOF:
                return 24;
            case 9:
                return 25;
            default:
                return 26;
        }
    }
    
    public Vector<String> getErrors(){
        return errors;
    }
    
    public Token getToken(){
        try{
            currentState = 0;
            lastState[0] = 0;
            char actual;
            while ((currentState != F) && (lastRead[0]<buffer.length)){               
                    lastState[0] = currentState;
                    actual = buffer[lastRead[0]];
                    lastRead[0] = lastRead[0]+1;
                    currentState = transitions[lastState[0]][mapChar(actual)]; 

                    tokenChars.append(actual);
                    //If it has a semantic action
                    if(actions[lastState[0]][mapChar(actual)] != E){
                        String err = acciones.elementAt(actions[lastState[0]][mapChar(actual)]).doAction();
                        if(err!=null){
                            errors.add(err);
                        }
                    }          
            }
            truncado = false;
            char lastCharRead = buffer[lastRead[0]-1];
            Token t;
            t = createToken(lastCharRead,lastState[0],tokenChars.toString());
            //t.print();
            tokenChars.delete(0, tokenChars.length());           
            return t;
        }
        catch(Exception e){
            e.printStackTrace();
            return null;
        }
    }
    
    public Token createToken(char lastCharRead, int lastState,String key1){
        String key = key1.toLowerCase();
        //Depending on what state we finished at ...
        switch (lastState) {
            //State 0
            case 0:
                //Depending on which char it was...
                switch (lastCharRead) {              
                    case '+': return new Token('+', null);  
                    case '-': return new Token('-', null);                        
                    case '/': return new Token('/', null);
                    case '(': return new Token('(', null);
                    case ')': return new Token(')', null);
                    case '[': return new Token('[', null);
                    case ']': return new Token(']', null);
                    case '{': return new Token('{', null);
                    case '}': return new Token('}', null);
                    case ';': return new Token(';', null);
                    case ',': return new Token(',', null);
                    case '"': return new Token('"', null);
                    case '=': return new Token('=', null);
                }
                break;
            //State 1    
            case 1: { 
                if (key.equals("if"))return new Token(IF,null);
                else if (key.equals("then"))return new Token(THEN,null);
                else if (key.equals("else"))return new Token(ELSE,null);
                else if (key.equals("print"))return new Token(PRINT,null);
                else if (key.equals("var"))return new Token(VAR,null);
                else if (key.equals("array"))return new Token(ARRAY,null);                
                else if (key.equals("double"))return new Token(DOUBLE,null);
                else if (key.equals("do"))return new Token(DO,null);                
                else if (key.equals("until"))return new Token(UNTIL,null);
                else return new Token(IDENTIFICADOR,key);
            }
            //State 2
            case 2: {
                return new Token(ASIG,null);
            }
            //State 3
            case 3: {
                if(lastCharRead == '=') return new Token(MAYI,null);
                else return new Token(MAY,null);
            }
            //State 4
            case 4: {
                if(lastCharRead == '=')
                    return new Token(MENI,null);
                else if (lastCharRead == '>')
                    return new Token(DIST,null);
                else return new Token(MEN,null);
            }
            //State 5
            case 5: {
                 return new Token('*',null);
            }
            //State 11,12,14
            case 11: case 12: case 14:{
                return new Token(DOUB,key);
            }                
            //State 15
            case 15: {
                return new Token(CADENA,key);
            }
            default: return new Token(E,null);
        }
        return new Token(E,null);
    
    }
    
    public int getLineNumber(){
        return lineNumber[0];
    }
    
    public TablaSimb getTable(){
        return table;
    }
    
}
